﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Windows.Media;
using System.Xml.Serialization;
using SSG.Tools;
using SSG.View;
using Color = System.Windows.Media.Color;

namespace SSG.Model
{
    /// <summary>
    ///   Settings object for the Generator
    /// </summary>
    [Serializable]
    [XmlInclude(typeof (Setting))]
    [XmlInclude(typeof (Setting.SettingValues))]
    public class GeneratorSettings : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        // ReSharper disable FieldCanBeMadeReadOnly.Local
        private string _destinationDirectory = null;
        private string _sourceDirectory = null;
        private string _filenamePattern = null;
        private string _sctHeaderlineDesignatorPattern = null;
        private string _colourSctSids = null;
        private string _colourSctStars = null;
        private string _colourSctTransitions = null;
        private Setting _sctSidOrder = null;
        private Setting _sctStarOrder = null;
        private Setting _sctTransitionOrder = null;
        [NonSerialized] private Color _colourKmlSids = Colors.Black;
        [NonSerialized] private Color _colourKmlStars = Colors.Red;
        [NonSerialized] private Color _colourKmlTransitions = Colors.Gold;
        [NonSerialized] private Color _colourKmlApproaches = Colors.WhiteSmoke;
        // ReSharper disable ConvertToConstant.Local
        private int _opacityFillKmlSids = 50;
        private int _opacityFillKmlStars = 50;
        private int _opacityFillKmlTransitions = 50;
        private int _opacityFillKmlApproaches = 50;
        private bool _generateEse = true;
        private bool _generateSct = true;
        private bool _generateKml = false;
        private bool _transitionsIncludeSids = true;
        private bool _transitionsIncludeStars = true;
        private bool _transitionsIncludeApproaches = true;
        private bool _extendedComments = false;
        private bool _ndbNameCorrection = true;
        private bool _trackNameWithoutSpaces = true;
        private bool _isBlacklistEnabled = false;
        private bool _useRunwayTracksSids = true;
        private bool _useRunwayTracksStars = true;
        private bool _useRunwayTracksTransitions = true;
        // ReSharper restore ConvertToConstant.Local
        // ReSharper restore FieldCanBeMadeReadOnly.Local
        private NameFilter _nameFilterSids = null;
        private NameFilter _nameFilterStars = null;
        private NameFilter _nameFilterTransitions = null;
        [NonSerialized] private IConsoleAndStatus _consoleAndStatus = null;
        public static GeneratorSettings DefaultSettings = new GeneratorSettings();

        /// <summary>
        /// Default constructor, required for serialization, and default settings.
        /// </summary>
        public GeneratorSettings()
        {
            this.SourceDirectory = "C:\\yourNavigraphPMDGDirectory\\";
            this.DestinationDirectory = "C:\\yourOutputDirectory\\";
            this.ResetGeneratingSettings();
            this.AirportGroups = new List<AirportsGroup>();
            this.ColourKmlSids = Colors.Black;
            this.ColourKmlStars = Colors.Red;
            this.ColourKmlTransitions = Colors.Gold;
            this.ColourKmlApproaches = Colors.WhiteSmoke;
        }

        /// <summary>
        /// Reset the generating settings
        /// </summary>
        public void ResetGeneratingSettings()
        {
            this.SctSidOrder = Setting.OrderByRunway;
            this.SctStarOrder = Setting.OrderByRunway;
            this.SctTransitionOrder = Setting.OrderByRunway;
            this.GenerateEse = true;
            this.GenerateSct = true;
            this.GenerateKml = false;
            this.NdbNameCorrection = true;
            this.TrackNameWithoutSpaces = true;
            this.ExtendedComments = true;
            this.TransitionsIncludeSids = true;
            this.TransitionsIncludeStars = true;
            this.TransitionsIncludeApproaches = true;
            this.ColourSctSids = null;
            this.ColourSctStars = null;
            this.ColourSctTransitions = null;
            this.UseRunwayTracksSids = true;
            this.UseRunwayTracksStars = true;
            this.UseRunwayTracksTransitions = true;
            this.SetDefaultFilePattern();
            this.SetDefaultSctHeaderlinePattern();
            this.NameFilterSids = new NameFilter {ModeIgnore = true, FilteredAsComments = true};
            this.NameFilterStars = new NameFilter {ModeIgnore = true, FilteredAsComments = true};
            this.NameFilterTransitions = new NameFilter {ModeInclude = true, NamesWithNumber = true, FilteredAsComments = true};
            this.FixBlacklist = this.FixBlacklist ?? new ObservableCollection<string>();
            this.IsBlacklistEnabled = false;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="consoleAndStatus">Optional output facility</param>
        public GeneratorSettings(IConsoleAndStatus consoleAndStatus) : this()
        {
            this._consoleAndStatus = consoleAndStatus;
        }

        /// <summary>
        /// Facility to log status and console messages.
        /// </summary>
        [XmlIgnore]
        public IConsoleAndStatus ConsoleAndStatus { get { return this._consoleAndStatus; } internal set { this._consoleAndStatus = value; } }

        /// <summary>
        /// Airport groups
        /// </summary>
        public List<AirportsGroup> AirportGroups { get; set; }

        /// <summary>
        /// Name filter for SIDs
        /// </summary>
        public NameFilter NameFilterSids
        {
            get { return this._nameFilterSids; }
            set
            {
                if (this._nameFilterSids == value) return;
                if (this._nameFilterSids != null) this._nameFilterSids.PropertyChanged -= this.NameFilterPropertyChanged;
                this._nameFilterSids = value;
                this._nameFilterSids.PropertyChanged += this.NameFilterPropertyChanged;
                this.OnPropertyChanged(ObjectTools.GetPropertyName(() => this.NameFilterSids));
            }
        }

        /// <summary>
        /// Name filter for STARs
        /// </summary>
        public NameFilter NameFilterStars
        {
            get { return this._nameFilterStars; }
            set
            {
                if (this._nameFilterStars == value) return;
                if (this._nameFilterStars != null) this._nameFilterStars.PropertyChanged -= this.NameFilterPropertyChanged;
                this._nameFilterStars = value;
                this._nameFilterStars.PropertyChanged += this.NameFilterPropertyChanged;
                this.OnPropertyChanged(ObjectTools.GetPropertyName(() => this.NameFilterStars));
            }
        }

        /// <summary>
        /// Name filter for Transitions
        /// </summary>
        public NameFilter NameFilterTransitions
        {
            get { return this._nameFilterTransitions; }
            set
            {
                if (this._nameFilterTransitions == value) return;
                if (this._nameFilterTransitions != null) this._nameFilterTransitions.PropertyChanged -= this.NameFilterPropertyChanged;
                this._nameFilterTransitions = value;
                this._nameFilterTransitions.PropertyChanged += this.NameFilterPropertyChanged;
                this.OnPropertyChanged(ObjectTools.GetPropertyName(() => this.NameFilterTransitions));
            }
        }

        /// <summary>
        /// Destination directory.
        /// </summary>
        public string DestinationDirectory
        {
            get { return this._destinationDirectory; }
            set
            {
                value = this.FixDirectoryString(value);
                this.SetValueAndFireOnPropertyChangeEvent(value, value != this._destinationDirectory, this.PropertyChanged, () => this.DestinationDirectory, true);
            }
        }

        /// <summary>
        ///   Source directory.
        /// </summary>
        public string SourceDirectory
        {
            get { return this._sourceDirectory; }
            set
            {
                value = this.FixDirectoryString(value);
                this.SetValueAndFireOnPropertyChangeEvent(value, value != this._sourceDirectory, this.PropertyChanged, () => this.SourceDirectory, true);
            }
        }

        /// <summary>
        /// Colour for SCT SIDs
        /// </summary>
        public string ColourSctSids { get { return this._colourSctSids; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._colourSctSids, this.PropertyChanged, () => this.ColourSctSids, true); } }

        /// <summary>
        /// Colour for SCT STARs
        /// </summary>
        public string ColourSctStars { get { return this._colourSctStars; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._colourSctStars, this.PropertyChanged, () => this.ColourSctStars, true); } }

        /// <summary>
        /// Colour for SCT Transitions
        /// </summary>
        public string ColourSctTransitions { get { return this._colourSctTransitions; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._colourSctTransitions, this.PropertyChanged, () => this.ColourSctTransitions, true); } }

        /// <summary>
        /// KML colour SIDs
        /// </summary>
        [XmlIgnore]
        public Color ColourKmlSids { get { return this._colourKmlSids; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._colourKmlSids, this.PropertyChanged, () => this.ColourKmlSids, true); } }

        /// <summary>
        /// KML colour STARs
        /// </summary>
        [XmlIgnore]
        public Color ColourKmlStars { get { return this._colourKmlStars; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._colourKmlStars, this.PropertyChanged, () => this.ColourKmlStars, true); } }

        /// <summary>
        /// KML colour transitions
        /// </summary>
        [XmlIgnore]
        public Color ColourKmlTransitions { get { return this._colourKmlTransitions; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._colourKmlTransitions, this.PropertyChanged, () => this.ColourKmlTransitions, true); } }

        /// <summary>
        /// KML colour Approaches
        /// </summary>
        [XmlIgnore]
        public Color ColourKmlApproaches { get { return this._colourKmlApproaches; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._colourKmlApproaches, this.PropertyChanged, () => this.ColourKmlApproaches, true); } }

        /// <summary>
        /// KML colour as RGB Hex
        /// </summary>
        public string ColourKmlSidsArgbHex
        {
            get { return this.ColourKmlSids.ToArgbHex(); }
            set
            {
                if (value == null) return;
                this.ColourKmlSids = value.FromArgbHex();
            }
        }

        /// <summary>
        /// KML colour as RGB Hex
        /// </summary>
        public string ColourKmlFillSidsArgbHex { get { return this.ColourKmlSidsArgbHex.SetOpacityForArgbHex(this.OpacityFillKmlSids); } }

        /// <summary>
        /// KML colour as RGB Hex
        /// </summary>
        public string ColourKmlStarsArgbHex
        {
            get { return this.ColourKmlStars.ToArgbHex(); }
            set
            {
                if (value == null) return;
                this.ColourKmlStars = value.FromArgbHex();
            }
        }

        /// <summary>
        /// KML colour as RGB Hex
        /// </summary>
        public string ColourKmlFillStarsArgbHex { get { return this.ColourKmlStarsArgbHex.SetOpacityForArgbHex(this.OpacityFillKmlStars); } }

        /// <summary>
        /// KML colour as RGB Hex
        /// </summary>
        public string ColourKmlTransitionsArgbHex
        {
            get { return this.ColourKmlTransitions.ToArgbHex(); }
            set
            {
                if (value == null) return;
                this.ColourKmlTransitions = value.FromArgbHex();
            }
        }

        /// <summary>
        /// KML colour as RGB Hex
        /// </summary>
        public string ColourKmlFillTransitionsArgbHex { get { return this.ColourKmlTransitionsArgbHex.SetOpacityForArgbHex(this.OpacityFillKmlTransitions); } }

        /// <summary>
        /// KML colour as RGB Hex
        /// </summary>
        public string ColourKmlApproachesArgbHex
        {
            get { return this.ColourKmlApproaches.ToArgbHex(); }
            set
            {
                if (value == null) return;
                this.ColourKmlApproaches = value.FromArgbHex();
            }
        }

        /// <summary>
        /// KML colour as RGB Hex
        /// </summary>
        public string ColourKmlFillApproachesArgbHex { get { return this.ColourKmlApproachesArgbHex.SetOpacityForArgbHex(this.OpacityFillKmlApproaches); } }

        /// <summary>
        /// Opacity for filling the SIDs
        /// </summary>
        public int OpacityFillKmlSids { get { return this._opacityFillKmlSids; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._opacityFillKmlSids, this.PropertyChanged, () => this.OpacityFillKmlSids, true); } }

        /// <summary>
        /// Opacity for filling the STARs
        /// </summary>
        public int OpacityFillKmlStars { get { return this._opacityFillKmlStars; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._opacityFillKmlStars, this.PropertyChanged, () => this.OpacityFillKmlStars, true); } }

        /// <summary>
        /// Opacity for filling the Transitions
        /// </summary>
        public int OpacityFillKmlTransitions { get { return this._opacityFillKmlTransitions; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._opacityFillKmlTransitions, this.PropertyChanged, () => this.OpacityFillKmlTransitions, true); } }

        /// <summary>
        /// Opacity for filling the Approaches
        /// </summary>
        public int OpacityFillKmlApproaches { get { return this._opacityFillKmlApproaches; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._opacityFillKmlApproaches, this.PropertyChanged, () => this.OpacityFillKmlApproaches, true); } }

        /// <summary>
        /// How to order SIDs.
        /// </summary>
        public Setting SctSidOrder
        {
            get { return this._sctSidOrder; }
            set
            {
                if (value != null) value = Setting.BySettingValue(value.Value); // make unique instance 
                this.SetValueAndFireOnPropertyChangeEvent(value, !this._sctSidOrder.NullSafeEquals(value), this.PropertyChanged, () => this.SctSidOrder, true);
            }
        }

        /// <summary>
        /// How to order STARs.
        /// </summary>
        public Setting SctStarOrder
        {
            get { return this._sctStarOrder; }
            set
            {
                if (value != null) value = Setting.BySettingValue(value.Value); // make unique instance 
                this.SetValueAndFireOnPropertyChangeEvent(value, !this._sctStarOrder.NullSafeEquals(value), this.PropertyChanged, () => this.SctStarOrder, true);
            }
        }

        /// <summary>
        /// How to order Transitions.
        /// </summary>
        public Setting SctTransitionOrder
        {
            get { return this._sctTransitionOrder; }
            set
            {
                if (value != null) value = Setting.BySettingValue(value.Value); // make unique instance 
                this.SetValueAndFireOnPropertyChangeEvent(value, !this._sctTransitionOrder.NullSafeEquals(value), this.PropertyChanged, () => this.SctTransitionOrder, true);
            }
        }

        /// <summary>
        /// Base file name.
        /// </summary>
        public string FilenamePattern
        {
            get { return this._filenamePattern; }
            set
            {
                if (string.IsNullOrWhiteSpace(value)) value = null;
                if (!String.IsNullOrEmpty(value)) value = value.Trim();
                this.SetValueAndFireOnPropertyChangeEvent(value, value != this._filenamePattern, this.PropertyChanged, () => this.FilenamePattern, true);
            }
        }

        /// <summary>
        /// List of unwanted fixes, low level just by string
        /// </summary>
        public ObservableCollection<string> FixBlacklist { get; set; }

        /// <summary>
        /// Generate ESE file?
        /// </summary>
        public bool GenerateEse { get { return this._generateEse; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._generateEse, this.PropertyChanged, () => this.GenerateEse, true); } }

        /// <summary>
        /// Generate SCT file?
        /// </summary>
        public bool GenerateSct { get { return this._generateSct; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._generateSct, this.PropertyChanged, () => this.GenerateSct, true); } }

        /// <summary>
        /// Generate KML file?
        /// </summary>
        public bool GenerateKml { get { return this._generateKml; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._generateKml, this.PropertyChanged, () => this.GenerateKml, true); } }

        /// <summary>
        /// Consider runway tracks?
        /// </summary>
        public bool UseRunwayTracksSids { get { return this._useRunwayTracksSids; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._useRunwayTracksSids, this.PropertyChanged, () => this.UseRunwayTracksSids, true); } }

        /// <summary>
        /// Consider runway tracks?
        /// </summary>
        public bool UseRunwayTracksStars { get { return this._useRunwayTracksStars; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._useRunwayTracksStars, this.PropertyChanged, () => this.UseRunwayTracksStars, true); } }

        /// <summary>
        /// Consider runway tracks?
        /// </summary>
        public bool UseRunwayTracksTransitions { get { return this._useRunwayTracksTransitions; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._useRunwayTracksTransitions, this.PropertyChanged, () => this.UseRunwayTracksTransitions, true); } }

        /// <summary>
        /// Extended comments?
        /// </summary>
        public bool ExtendedComments { get { return this._extendedComments; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._extendedComments, this.PropertyChanged, () => this.ExtendedComments, true); } }

        /// <summary>
        /// Include SID Transitions?
        /// </summary>
        public bool TransitionsIncludeSids { get { return this._transitionsIncludeSids; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._transitionsIncludeSids, this.PropertyChanged, () => this.TransitionsIncludeSids, true); } }

        /// <summary>
        /// Include SID Transitions?
        /// </summary>
        public bool TransitionsIncludeStars { get { return this._transitionsIncludeStars; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._transitionsIncludeStars, this.PropertyChanged, () => this.TransitionsIncludeStars, true); } }

        /// <summary>
        /// Include Approach Transitions?
        /// </summary>
        public bool TransitionsIncludeApproaches { get { return this._transitionsIncludeApproaches; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._transitionsIncludeApproaches, this.PropertyChanged, () => this.TransitionsIncludeApproaches, true); } }

        /// <summary>
        /// Substitute NDB names, e.g. RTBNB -> RTB NDB (see EDDN)
        /// </summary>
        public bool NdbNameCorrection { get { return this._ndbNameCorrection; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._ndbNameCorrection, this.PropertyChanged, () => this.NdbNameCorrection, true); } }

        /// <summary>
        /// Track name without spaces?
        /// </summary>
        public bool TrackNameWithoutSpaces { get { return this._trackNameWithoutSpaces; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._trackNameWithoutSpaces, this.PropertyChanged, () => this.TrackNameWithoutSpaces, true); } }

        /// <summary>
        /// Blacklist enabled?
        /// </summary>
        public bool IsBlacklistEnabled { get { return this._isBlacklistEnabled; } set { this.SetValueAndFireOnPropertyChangeEvent(value, value != this._isBlacklistEnabled, this.PropertyChanged, () => this.IsBlacklistEnabled, true); } }

        /// <summary>
        /// All transistions included?
        /// </summary>
        [XmlIgnore]
        public bool TransitionsIncludeAll { get { return this.TransitionsIncludeApproaches && this.TransitionsIncludeSids && this.TransitionsIncludeStars; } }

        /// <summary>
        /// File containing the runways
        /// </summary>
        public string RunwaysPmdgFile { get { return this.NavaidDirectory + "wpnavapt.txt"; } }

        /// <summary>
        /// File containing the navaids
        /// </summary>
        public string NavaidsPmdgFile { get { return this.NavaidDirectory + "wpnavaid.txt"; } }

        /// <summary>
        /// File containing the airports
        /// </summary>
        public string AirportsPmdgFile { get { return this.NavaidDirectory + "airports.dat"; } }

        /// <summary>
        /// Directory containing SID / STAR files.
        /// </summary>
        [XmlIgnore]
        public string SidStarDirectory { get { return this._sourceDirectory + "SIDSTARS" + FileTools.DirectorySeperator; } }

        /// <summary>
        /// Directory containing Navaids files.
        /// </summary>
        [XmlIgnore]
        public string NavaidDirectory { get { return this._sourceDirectory + "NavData" + FileTools.DirectorySeperator; } }

        /// <summary>
        /// Existing SID / STAR Directory?
        /// </summary>
        [XmlIgnore]
        public bool ExistsSidStarDirectory { get { return !string.IsNullOrEmpty(this.SourceDirectory) && Directory.Exists(this.SidStarDirectory); } }

        /// <summary>
        /// Existing SID / STAR Directory?
        /// </summary>
        [XmlIgnore]
        public bool ExistsNavaidsDirectory { get { return !string.IsNullOrEmpty(this.SourceDirectory) && Directory.Exists(this.NavaidDirectory); } }

        /// <summary>
        /// Existing destination directory?
        /// </summary>
        [XmlIgnore]
        public bool ExistsDestinationDirectory { get { return !string.IsNullOrEmpty(this.DestinationDirectory) && Directory.Exists(this.DestinationDirectory); } }

        /// <summary>
        /// Existing runway file?
        /// </summary>
        [XmlIgnore]
        public bool ExistsRunwaysFile { get { return !string.IsNullOrEmpty(this.SourceDirectory) && File.Exists(this.RunwaysPmdgFile); } }

        /// <summary>
        /// Existing navaid file?
        /// </summary>
        [XmlIgnore]
        public bool ExistsNavaidsFile { get { return !string.IsNullOrEmpty(this.SourceDirectory) && File.Exists(this.NavaidsPmdgFile); } }

        /// <summary>
        /// Existing runway file?
        /// </summary>
        [XmlIgnore]
        public bool ExistsAirportsFile { get { return !string.IsNullOrEmpty(this.SourceDirectory) && File.Exists(this.AirportsPmdgFile); } }

        /// <summary>
        /// SID/STAR/TRANS header line intro 
        /// </summary>
        /// <seealso cref="SetDefaultSctHeaderlinePattern"/>
        [XmlIgnore]
        public string SctHeaderlineDesignatorPattern
        {
            get { return this._sctHeaderlineDesignatorPattern; }
            set
            {
                if (string.IsNullOrWhiteSpace(value)) value = null;
                if (!String.IsNullOrEmpty(value)) value = value.Trim();
                this.SetValueAndFireOnPropertyChangeEvent(value, value != this._sctHeaderlineDesignatorPattern, this.PropertyChanged, () => this.SctHeaderlineDesignatorPattern, true);
            }
        }

        /// <summary>
        /// Icon colour 
        /// </summary>
        [XmlIgnore]
        public string KmlIconColour { get { return "ff00ffff"; } }

        /// <summary>
        /// Label colour 
        /// </summary>
        [XmlIgnore]
        public string KmlLabelColour { get { return "ff00ffff"; } }

        /// <summary>
        /// Line width 
        /// </summary>
        [XmlIgnore]
        public int KmlLineWidth { get { return 2; } }

        /// <summary>
        /// Climb rate in ft/km.
        /// </summary>
        public double ClimbRateFtPerKm
        {
            get { return Units.ClimbRateFtPerKm(300, 2500); }
        }

        /// <summary>
        /// VOR DME
        /// </summary>
        [XmlIgnore]
        public string SymbolVorDmeUrl
        {
            get
            {
                return "http://maps.google.com/mapfiles/kml/shapes/square.png";

                // I have tried  SVG -> does not work
                // highest resolution gives best result
                // return "http://upload.wikimedia.org/wikipedia/commons/thumb/d/d8/VOR-DME.svg/2000px-VOR-DME.svg.png";
                // return "http://upload.wikimedia.org/wikipedia/commons/d/d8/VOR-DME.svg";
            }
        }

        /// <summary>
        /// VOR
        /// </summary>
        [XmlIgnore]
        public string SymbolVorUrl
        {
            get
            {
                return "http://maps.google.com/mapfiles/kml/shapes/polygon.png";
                // return "http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Pictogram_VOR.svg/2000px-Pictogram_VOR.svg.png";
            }
        }

        /// <summary>
        /// VORTAC
        /// </summary>
        [XmlIgnore]
        public string SymbolVorTacUrl
        {
            get
            {
                return "http://maps.google.com/mapfiles/kml/shapes/open-diamond.png";
                // return "http://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/Pictogram_VORTAC.svg/2000px-Pictogram_VORTAC.svg.png";
            }
        }

        /// <summary>
        /// DME
        /// </summary>
        [XmlIgnore]
        public string SymbolNdbUrl
        {
            get
            {
                return "http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png";
                // return "http://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/NDB_Symbol.svg/2000px-NDB_Symbol.svg.png";
            }
        }

        /// <summary>
        /// Symbol used for waypoints
        /// </summary>
        [XmlIgnore]
        public string SymbolWaypointUrl { get { return "http://maps.google.com/mapfiles/kml/shapes/triangle.png"; } }

        /// <summary>
        /// Symbol used for runways
        /// </summary>
        [XmlIgnore]
        public string SymbolRunwayUrl { get { return "http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png"; } }

        /// <summary>
        /// Symbol used for legs
        /// </summary>
        [XmlIgnore]
        public string SymbolLegUrl { get { return "http://maps.google.com/mapfiles/kml/pal5/icon5.png"; } }

        /// <summary>
        /// Set the default filename pattern
        /// </summary>
        public void SetDefaultFilePattern()
        {
            this.FilenamePattern = "region_" + Generator.PlaceholderType + "_" + Generator.PlaceholderAirportIcao + "_" + Generator.PlaceholderAirac + "_" + Generator.PlaceholderFiletype + "." + Generator.PlaceholderAppendix; // edmm_stars_eddm_ese.txt
        }

        /// <summary>
        /// Pattern for SCT headerline
        /// </summary>
        /// <seealso cref="SctHeaderlineDesignatorPattern"/>
        public void SetDefaultSctHeaderlinePattern()
        {
            this.SctHeaderlineDesignatorPattern = Generator.PlaceholderType + " " + Generator.PlaceholderAirportIcao + " " + Generator.PlaceholderRunway + " " + Generator.PlaceholderTrackName;
        }

        /// <summary>
        /// Fixing given directory string
        /// </summary>
        /// <param name="candidate"></param>
        /// <returns></returns>
        private string FixDirectoryString(string candidate)
        {
            if (string.IsNullOrWhiteSpace(candidate)) candidate = null;
            if (string.IsNullOrEmpty(candidate)) return candidate;
            if (!candidate.EndsWith(FileTools.DirectorySeperator)) candidate += FileTools.DirectorySeperator;
            return candidate.RemoveMultipleBackslashes();
        }

        /// <summary>
        /// Order as per type
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public Setting GetSctOrder(Type t)
        {
            if (t == null) throw new ArgumentNullException("t");
            if (typeof (Sid) == t) return this.SctSidOrder;
            if (typeof (Star) == t) return this.SctStarOrder;
            if (typeof (Transition) == t) return this.SctTransitionOrder;
            return null;
        }

        /// <summary>
        /// Order as per track type
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public Setting GetSctOrder(Procedure t)
        {
            if (t == null) return null;
            return this.GetSctOrder(t.GetType());
        }

        /// <summary>
        /// Use runway track, as per type
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public bool UseRunwayTracks(Type t)
        {
            if (t == null) throw new ArgumentNullException("t");
            if (typeof (Sid) == t) return this.UseRunwayTracksSids;
            if (typeof (Star) == t) return this.UseRunwayTracksStars;
            if (typeof (Transition) == t) return this.UseRunwayTracksTransitions;
            return false;
        }

        /// <summary>
        /// Colour by type
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public string GetSctColor(Type t)
        {
            if (t == null) throw new ArgumentNullException("t");
            if (typeof (Sid) == t) return this.ColourSctSids;
            if (typeof (Star) == t) return this.ColourSctStars;
            if (typeof (Transition) == t) return this.ColourSctTransitions;
            throw new InvalidOperationException("Unknown type " + t.FullName);
        }

        /// <summary>
        /// Colour by type
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public Color GetKmlColor(Type t)
        {
            if (t == null) throw new ArgumentNullException("t");
            if (typeof (Sid) == t) return this.ColourKmlSids;
            if (typeof (Star) == t) return this.ColourKmlStars;
            if (typeof (Transition) == t) return this.ColourKmlTransitions;
            if (typeof (Approach) == t) return this.ColourKmlApproaches;
            throw new InvalidOperationException("Unknown type " + t.FullName);
        }

        /// <summary>
        /// Opacity as of type
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public int GetKmlFillOpacity(Type t)
        {
            if (t == null) throw new ArgumentNullException("t");
            if (typeof (Sid) == t) return this.OpacityFillKmlSids;
            if (typeof (Star) == t) return this.OpacityFillKmlStars;
            if (typeof (Transition) == t) return this.OpacityFillKmlTransitions;
            if (typeof (Approach) == t) return this.OpacityFillKmlApproaches;
            throw new InvalidOperationException("Unknown type " + t.FullName);
        }

        /// <summary>
        /// Colour by type
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public string GetKmlColorArgbHex(Type t)
        {
            return this.GetKmlColor(t).ToArgbHex();
        }

        /// <summary>
        /// Colour by type
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public string GetKmlColorAbgrHex(Type t)
        {
            return this.GetKmlColor(t).ToArgbHex().ArgbToAbgrHex();
        }

        /// <summary>
        /// Colour by type
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public string GetKmlFillColorAbgrHex(Type t)
        {
            int o = this.GetKmlFillOpacity(t);
            return this.GetKmlColor(t).ToArgbHex().SetOpacityForArgbHex(o).ArgbToAbgrHex();
        }

        /// <summary>
        /// Get corresponding name filter
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public NameFilter GetNameFilter(Type t)
        {
            if (typeof (Sid) == t) return this.NameFilterSids;
            if (typeof (Star) == t) return this.NameFilterStars;
            if (typeof (Transition) == t) return this.NameFilterTransitions;
            return null;
        }

        /// <summary>
        /// Property chnaged handling.
        /// </summary>
        /// <param name="propertyName"></param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Name filter property has been changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void NameFilterPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.OnPropertyChanged(e.PropertyName);
        }
    }
}